home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Library / Manuels & Misc / Assembly / AOA.ZIP / CH24 / SGDI.ASM < prev    next >
Encoding:
Assembly Source File  |  1994-07-28  |  17.9 KB  |  812 lines

  1.         .286
  2.         page    58, 132
  3.         name    SGDI
  4.         title    SGDI Driver for Standard Game Adapter Card
  5.         subttl    This Program is Public Domain Material.
  6.  
  7. ; SGDI.EXE
  8. ;
  9. ;    Usage:
  10. ;        SDGI
  11. ;
  12. ; This program loads a TSR which patches INT 15 so arbitrary game programs
  13. ; can read the joystick in a portable fashion.
  14. ;
  15. ;
  16. ; We need to load cseg in memory before any other segments!
  17.  
  18. cseg        segment    para public 'code'
  19. cseg        ends
  20.  
  21.  
  22. ; Initialization code, which we do not need except upon initial load,
  23. ; goes in the following segment:
  24.  
  25. Initialize    segment    para public 'INIT'
  26. Initialize    ends
  27.  
  28. ; UCR Standard Library routines which get dumped later on.
  29.  
  30.         .xlist
  31.         include        stdlib.a
  32.         includelib    stdlib.lib
  33.         .list
  34.  
  35. sseg        segment    para stack 'stack'
  36. sseg        ends
  37.  
  38. zzzzzzseg    segment    para public 'zzzzzzseg'
  39. zzzzzzseg    ends
  40.  
  41.  
  42.  
  43. CSEG        segment    para public 'CODE'
  44.         assume    cs:cseg, ds:nothing
  45.  
  46. wp        equ    <word ptr>
  47. byp        equ    <byte ptr>
  48.  
  49. Int15Vect    dd    0
  50.  
  51. PSP        dw    ?
  52.  
  53. ; Port addresses for a typical joystick card:
  54.  
  55. JoyPort        equ    201h
  56. JoyTrigger    equ    201h
  57.  
  58. ; Data structure to hold information about each pot.
  59. ; (mainly for calibration and normalization purposes).
  60.  
  61. Pot        struc
  62. PotMask        db    0            ;Pot mask for hardware.
  63. DidCal        db    0            ;Is this pot calibrated?
  64. min        dw    5000            ;Minimum pot value
  65. max        dw    0            ;Max pot value
  66. center        dw    0            ;Pot value in the middle
  67. Pot        ends
  68.  
  69. ; Variables for each of the pots.  Must initialize the masks so they
  70. ; mask out all the bits except the incomming bit for each pot.
  71.  
  72. Pot0        Pot    <1>
  73. Pot1        Pot    <2>
  74. Pot2        Pot    <4>
  75. Pot3        Pot    <8>
  76.  
  77.  
  78.  
  79. ; The IDstring address gets passed back to the caller on a testpresence
  80. ; call.  The four bytes before the IDstring must contain the serial number
  81. ; and current driver number.
  82.  
  83. SerialNumber    db    0,0,0
  84. IDNumber    db    0
  85. IDString    db    "Standard SGDI Driver",0
  86.         db    "Public Domain Driver Written by Randall L. Hyde",0
  87.  
  88.  
  89. ;============================================================================
  90. ;
  91. ; ReadPots- AH contains a bit mask to determine which pots we should read.
  92. ;        Bit 0 is one if we should read pot 0, bit 1 is one if we should
  93. ;        read pot 1, bit 2 is one if we should read pot 2, bit 3 is one
  94. ;        if we should read pot 3.  All other bits will be zero.
  95. ;
  96. ;    This code returns the pot values in SI, BX, BP, and DI for Pot 0, 1,
  97. ;    2, & 3.
  98. ;
  99.  
  100. ReadPots    proc    near
  101.         sub    bp, bp
  102.         mov    si, bp
  103.         mov    di, bp
  104.         mov    bx, bp
  105.  
  106. ; Wait for any previous signals to finish up before trying to read this
  107. ; guy.  It is possible that the last pot we read was very short.  However,
  108. ; the trigger signal starts timers running for all four pots.  This code
  109. ; terminates as soon as the current pot times out.  If the user immediately
  110. ; reads another pot, it is quite possible that the new pot's timer has
  111. ; not yet expired from the previous read.  The following loop makes sure we
  112. ; aren't measuring the time from the previous read.
  113.  
  114.         mov    dx, JoyPort
  115.         mov    cx, 400h
  116. Wait4Clean:    in    al, dx
  117.         and    al, 0Fh
  118.         loopnz    Wait4Clean
  119.  
  120. ; Okay, read the pots.  The following code triggers the 558 timer chip
  121. ; and then sits in a loop until all four pot bits (masked with the pot mask
  122. ; in AL) become zero.  Each time through this loop that one or more of these
  123. ; bits contain zero, this loop increments the corresponding register(s).
  124.  
  125.         mov    dx, JoyTrigger
  126.         out    dx, al        ;Trigger pots
  127.         mov    dx, JoyPort
  128.         mov    cx, 1000h    ;Don't let this go on forever.
  129. PotReadLoop:    in    al, dx
  130.         and    al, ah
  131.         jz    PotReadDone
  132.         shr    al, 1
  133.         adc    si, 0        ;Increment SI if pot 0 still active.
  134.         shr    al, 1
  135.         adc    bx, 0        ;Increment BX if pot 1 still active.
  136.         shr    al, 1
  137.         adc    bp, 0        ;Increment BP if pot 2 still active.
  138.         shr    al, 1
  139.         adc    di, 0        ;Increment DI if pot 3 still active.
  140.         loop    PotReadLoop    ;Stop, eventually, if funny hardware.
  141.  
  142.         and    si, 0FFFh    ;If we drop through to this point,
  143.         and    bx, 0FFFh    ; one or more pots timed out (usually
  144.         and    bp, 0FFFh    ; because they are not connected).
  145.         and    di, 0FFFh    ; The reg contains 4000h, set it to 0.
  146. PotReadDone:
  147.         ret
  148. ReadPots    endp
  149.  
  150.  
  151.  
  152. ;----------------------------------------------------------------------------
  153. ;
  154. ; Normalize-     BX contains a pointer to a pot structure, AX contains
  155. ;        a pot value.  Normalize that value according to the
  156. ;        calibrated pot.
  157. ;
  158. ; Note: DS must point at cseg before calling this routine.
  159.  
  160.  
  161.         assume    ds:cseg
  162. Normalize    proc    near
  163.         push    cx
  164.  
  165. ; Sanity check to make sure the calibration process went okay.
  166.  
  167.         cmp    [bx].Pot.DidCal, 0    ;Is this pot calibrated?
  168.         je    BadNorm            ;If not, quit.
  169.  
  170.         mov    dx, [bx].Pot.Center    ;Do a sanity check on the
  171.         cmp    dx, [bx].Pot.Min    ; min, center, and max
  172.         jbe    BadNorm            ; values to make sure
  173.         cmp    dx, [bx].Pot.Max    ; min < center < max.
  174.         jae    BadNorm
  175.  
  176. ; Clip the value if it is out of range.
  177.  
  178.         cmp    ax, [bx].Pot.Min    ;If the value is less than
  179.         ja    MinOkay            ; the minimum value, set it
  180.         mov    ax, [bx].Pot.Min    ; to the minimum value.
  181. MinOkay:
  182.  
  183.         cmp    ax, [bx].Pot.Max    ;If the value is greater than
  184.         jb    MaxOkay            ; the maximum value, set it
  185.         mov    ax, [bx].Pot.Max    ; to the maximum value.
  186. MaxOkay:
  187.  
  188. ; Scale this guy around the center:
  189.  
  190.         cmp    ax, [bx].Pot.Center    ;See if less than or greater
  191.         jb    Lower128        ; than centered value.
  192.  
  193. ; Okay, current reading is greater than the centered value, scale the reading
  194. ; into the range 128..255 here:
  195.  
  196.         sub    ax, [bx].Pot.Center
  197.         mov    dl, ah            ;Multiply by 128
  198.         mov    ah, al
  199.         mov    dh, 0
  200.         mov    al, dh
  201.         shr    dl, 1
  202.         rcr    ax, 1
  203.         mov    cx, [bx].Pot.Max
  204.         sub    cx, [bx].Pot.Center
  205.         jz    BadNorm            ;Prevent division by zero.
  206.         div    cx            ;Compute normalized value.
  207.         add    ax, 128            ;Scale to range 128..255.
  208.         cmp    ah, 0
  209.         je    NormDone
  210.         mov    ax, 0ffh    ;Result must fit in 8 bits!
  211.         jmp    NormDone
  212.  
  213. ; If the reading is below the centered value, scale it into the range
  214. ; 0..127 here:
  215.  
  216. Lower128:    sub    ax, [bx].Pot.Min
  217.         mov    dl, ah
  218.         mov    ah, al
  219.         mov    dh, 0
  220.         mov    al, dh
  221.         shr    dl, 1
  222.         rcr    ax, 1
  223.         mov    cx, [bx].Pot.Center
  224.         sub    cx, [bx].Pot.Min
  225.         jz    BadNorm
  226.         div    cx
  227.         cmp    ah, 0
  228.         je    NormDone
  229.         mov    ax, 0ffh
  230.         jmp    NormDone
  231.  
  232. ; If something went wrong, return zero as the normalized value.
  233.  
  234. BadNorm:    sub    ax, ax
  235.  
  236. NormDone:    pop    cx
  237.         ret
  238. Normalize    endp
  239.         assume    ds:nothing
  240.  
  241. ;============================================================================
  242. ; INT 15h handler functions.
  243. ;============================================================================
  244. ;
  245. ; Although these are defined as near procs, they are not really procedures.
  246. ; The MyInt15 code jumps to each of these with BX, a far return address, and
  247. ; the flags sitting on the stack.  Each of these routines must handle the
  248. ; stack appropriately.
  249. ;
  250. ;----------------------------------------------------------------------------
  251. ; BIOS- Handles the two BIOS calls, DL=0 to read the switches, DL=1 to
  252. ;    read the pots.  For the BIOS routines, we'll ignore the cooley
  253. ;    switch (the hat) and simply read the other four switches.
  254.  
  255. BIOS        proc    near
  256.         cmp    dl, 1        ;See if switch or pot routine.
  257.         jb    Read4Sw
  258.         je    ReadBIOSPots
  259.  
  260. ; If not a valid BIOS call, jump to the original INT 15 handler and
  261. ; let it take care of this call.
  262.  
  263.         pop    bx
  264.         jmp    cs:Int15Vect    ;Let someone else handle it!
  265.  
  266. ; BIOS read switches function.
  267.  
  268. Read4Sw:    push    dx
  269.         mov    dx, JoyPort
  270.         in    al, dx
  271.         and    al, 0F0h    ;Return only switch values.
  272.         pop    dx
  273.         pop    bx
  274.         iret
  275.  
  276. ; BIOS read pots function.
  277.  
  278. ReadBIOSPots:    pop    bx        ;Return a value in BX!
  279.         push    si
  280.         push    di
  281.         push    bp
  282.         mov    ah, 0Fh        ;Read all four pots.
  283.         call    ReadPots
  284.         mov    ax, si
  285.         mov    cx, bp        ;BX already contains pot 1 reading.
  286.         mov    dx, di
  287.         pop    bp
  288.         pop    di
  289.         pop    si
  290.         iret
  291. BIOS        endp
  292.  
  293. ;----------------------------------------------------------------------------
  294. ;
  295. ; ReadPot-    On entry, DL contains a pot number to read.
  296. ;        Read and normalize that pot and return the result in AL.
  297.  
  298.         assume    ds:cseg
  299. ReadPot        proc    near
  300. ;;;;;;;;;;    push    bx        ;Already on stack.
  301.         push    ds
  302.         push    cx
  303.         push    dx
  304.         push    si
  305.         push    di
  306.         push    bp
  307.  
  308.         mov    bx, cseg
  309.         mov    ds, bx
  310.  
  311. ; If dl = 0, read and normalize the value for pot 0, if not, try some
  312. ; other pot.
  313.  
  314.         cmp    dl, 0
  315.         jne    Try1
  316.         mov    ah, Pot0.PotMask    ;Get bit for this pot.
  317.         call    ReadPots        ;Read pot 0.
  318.         lea    bx, Pot0        ;Pointer to pot data.
  319.         mov    ax, si            ;Get pot 0 reading.
  320.         call    Normalize        ;Normalize to 0..FFh.
  321.         jmp    GotPot            ;Return to caller.
  322.  
  323. ; Test for DL=1 here (read and normalize pot 1).
  324.  
  325. Try1:        cmp    dl, 1
  326.         jne    Try2
  327.         mov    ah, Pot1.PotMask
  328.         call    ReadPots
  329.         mov    ax, bx
  330.         lea    bx, Pot1
  331.         call    Normalize
  332.         jmp    GotPot
  333.  
  334. ; Test for DL=2 here (read and normalize pot 2).
  335.  
  336. Try2:        cmp    dl, 2
  337.         jne    Try3
  338.         mov    ah, Pot2.PotMask
  339.         call    ReadPots
  340.         lea    bx, Pot2
  341.         mov    ax, bp
  342.         call    Normalize
  343.         jmp    GotPot
  344.  
  345. ; Test for DL=3 here (read and normalize pot 3).
  346.  
  347. Try3:        cmp    dl, 3
  348.         jne    BadPot
  349.         mov    ah, Pot3.PotMask
  350.         call    ReadPots
  351.         lea    bx, Pot3
  352.         mov    ax, di
  353.         call    Normalize
  354.         jmp    GotPot
  355.  
  356. ; Bad value in DL if we drop to this point.  The standard game card
  357. ; only supports four pots.
  358.  
  359. BadPot:        sub    ax, ax        ;Pot not available, return zero.
  360. GotPot:        pop    bp
  361.         pop    di
  362.         pop    si
  363.         pop    dx
  364.         pop    cx
  365.         pop    ds
  366.         pop    bx
  367.         iret
  368. ReadPot        endp
  369.         assume    ds:nothing
  370.  
  371.  
  372. ;----------------------------------------------------------------------------
  373. ;
  374. ; ReadRaw-    On entry, DL contains a pot number to read.
  375. ;        Read that pot and return the unnormalized result in AX.
  376.  
  377.         assume    ds:cseg
  378. ReadRaw        proc    near
  379. ;;;;;;;;;;    push    bx        ;Already on stack.
  380.         push    ds
  381.         push    cx
  382.         push    dx
  383.         push    si
  384.         push    di
  385.         push    bp
  386.  
  387.         mov    bx, cseg
  388.         mov    ds, bx
  389.  
  390. ; This code is almost identical to the ReadPot code.  The only difference
  391. ; is that we don't bother normalizing the result and (of course) we return
  392. ; the value in AX rather than AL.
  393.  
  394.         cmp    dl, 0
  395.         jne    Try1
  396.         mov    ah, Pot0.PotMask
  397.         call    ReadPots
  398.         mov    ax, si
  399.         jmp    GotPot
  400.  
  401. Try1:        cmp    dl, 1
  402.         jne    Try2
  403.         mov    ah, Pot1.PotMask
  404.         call    ReadPots
  405.         mov    ax, bx
  406.         jmp    GotPot
  407.  
  408. Try2:        cmp    dl, 2
  409.         jne    Try3
  410.         mov    ah, Pot2.PotMask
  411.         call    ReadPots
  412.         mov    ax, bp
  413.         jmp    GotPot
  414.  
  415. Try3:        cmp    dl, 3
  416.         jne    BadPot
  417.         mov    ah, Pot3.PotMask
  418.         call    ReadPots
  419.         mov    ax, di
  420.         jmp    GotPot
  421.  
  422. BadPot:        sub    ax, ax        ;Pot not available, return zero.
  423. GotPot:        pop    bp
  424.         pop    di
  425.         pop    si
  426.         pop    dx
  427.         pop    cx
  428.         pop    ds
  429.         pop    bx
  430.         iret
  431. ReadRaw        endp
  432.         assume    ds:nothing
  433.  
  434.  
  435. ;----------------------------------------------------------------------------
  436. ; Read4Pots-    Reads pots zero, one, two, and three returning their
  437. ;        values in AL, AH, DL, and DH.
  438. ;
  439. ;        On entry, AL contains the pot mask to select which pots
  440. ;        we should read (bit 0=1 for pot 0, bit 1=1 for pot 1, etc).
  441.  
  442. Read4Pots    proc    near
  443. ;;;;;;;;;;;    push    bx        ;Already on stack
  444.         push    ds
  445.         push    cx
  446.         push    si
  447.         push    di
  448.         push    bp
  449.  
  450.         mov    dx, cseg
  451.         mov    ds, dx
  452.  
  453.         mov    ah, al
  454.         call    ReadPots
  455.  
  456.         push    bx            ;Save pot 1 reading.
  457.         mov    ax, si            ;Get pot 0 reading.
  458.         lea    bx, Pot0        ;Point bx at pot0 vars.
  459.         call    Normalize        ;Normalize.
  460.         mov    cl, al            ;Save for later.
  461.  
  462.         pop    ax            ;Retreive pot 1 reading.
  463.         lea    bx, Pot1
  464.         call    Normalize
  465.         mov    ch, al            ;Save normalized value.
  466.  
  467.         mov    ax, bp
  468.         lea    bx, Pot2
  469.         call    Normalize
  470.         mov    dl, al            ;Pot 2 value.
  471.  
  472.         mov    ax, di
  473.         lea    bx, Pot3
  474.         call    Normalize
  475.         mov    dh, al            ;Pot 3 value.
  476.         mov    ax, cx            ;Pots 0 and 1.
  477.  
  478.         pop    bp
  479.         pop    di
  480.         pop    si
  481.         pop    cx
  482.         pop    ds
  483.         pop    bx
  484.         iret
  485. Read4Pots    endp
  486.  
  487.  
  488.  
  489.  
  490. ;----------------------------------------------------------------------------
  491. ; CalPot-    Calibrate the pot specified by DL.  On entry, AL contains
  492. ;        the minimum pot value (it better be less than 256!), BX
  493. ;        contains the maximum pot value, and CX contains the centered
  494. ;        pot value.
  495.  
  496.         assume    ds:cseg
  497. CalPot        proc    near
  498.         pop    bx        ;Retrieve maximum value
  499.         push    ds
  500.         push    si
  501.         mov    si, cseg
  502.         mov    ds, si
  503.  
  504. ; Sanity check on parameters, sort them in ascending order:
  505.  
  506.         mov    ah, 0
  507.         cmp    bx, cx            ;Make sure center < max
  508.         ja    GoodMax
  509.         xchg    bx, cx
  510. GoodMax:    cmp    ax, cx            ;Make sure min < center.
  511.         jb    GoodMin            ; (note: may make center<max).
  512.         xchg    ax, cx
  513. GoodMin:    cmp    cx, bx            ;Again, be sure center < max.
  514.         jb    GoodCenter
  515.         xchg    cx, bx
  516. GoodCenter:
  517.  
  518.  
  519. ; Okay, figure out who were supposed to calibrate:
  520.  
  521.         lea    si, Pot0
  522.         cmp    dl, 1
  523.         jb    DoCal            ;Branch if this is pot 0
  524.         lea    si, Pot1
  525.         je    DoCal            ;Branch if this is pot 1
  526.         lea    si, Pot2
  527.         cmp    dl, 3
  528.         jb    DoCal            ;Branch if this is pot 2
  529.         jne    CalDone            ;Branch if not pot 3
  530.         lea    si, Pot3
  531.  
  532. DoCal:        mov    [si].Pot.min, ax    ;Store away the minimum,
  533.         mov    [si].Pot.max, bx    ; maximum, and
  534.         mov    [si].Pot.center, cx    ; centered values.
  535.         mov    [si].Pot.DidCal, 1    ;Note we've cal'd this pot.
  536. CalDone:    pop    si
  537.         pop    ds
  538.         iret
  539. CalPot        endp
  540.         assume    ds:nothing
  541.  
  542.  
  543. ;----------------------------------------------------------------------------
  544. ; TestCal-    Just checks to see if the pot specified by DL has already
  545. ;        been calibrated.
  546.  
  547.         assume    ds:cseg
  548. TestCal        proc    near
  549. ;;;;;;;;    push    bx        ;Already on stack
  550.         push    ds
  551.         mov    bx, cseg
  552.         mov    ds, bx
  553.  
  554.         sub    ax, ax        ;Assume no calibration (also zeros AH)
  555.         lea    bx, Pot0    ;Get the address of the specified
  556.         cmp    dl, 1        ; pot's data structure into the
  557.         jb    GetCal        ; BX register.
  558.         lea    bx, Pot1
  559.         je    GetCal
  560.         lea    bx, Pot2
  561.         cmp    dl, 3
  562.         jb    GetCal
  563.         jne    BadCal
  564.         lea    bx, Pot3
  565.  
  566. GetCal:        mov    al, [bx].Pot.DidCal
  567. BadCal:        pop    ds
  568.         pop    bx
  569.         iret
  570. TestCal        endp
  571.         assume    ds:nothing
  572.  
  573.  
  574. ;----------------------------------------------------------------------------
  575. ;
  576. ; ReadSw-    Reads the switch whose switch number appears in DL.
  577.  
  578. ReadSw        proc    near
  579. ;;;;;;;        push    bx        ;Already on stack
  580.         push    cx
  581.  
  582.         sub    ax, ax        ;Assume no such switch.
  583.         cmp    dl, 3          ;Return if the switch number is
  584.         ja    NotDown        ; greater than three.
  585.  
  586.         mov    cl, dl        ;Save switch to read.
  587.         add    cl, 4        ;Move from position four down to zero.
  588.         mov    dx, JoyPort
  589.         in    al, dx        ;Read the switches.
  590.         shr    al, cl        ;Move desired switch bit into bit 0.
  591.         xor    al, 1        ;Invert so sw down=1.
  592.         and    ax, 1        ;Remove other junk bits.
  593. NotDown:    pop    cx
  594.         pop    bx
  595.         iret
  596. ReadSw        endp
  597.  
  598.  
  599. ;----------------------------------------------------------------------------
  600. ;
  601. ; Read16Sw-    Reads all four switches and returns their values in AX.
  602.  
  603. Read16Sw    proc    near
  604. ;;;;;;;;    push    bx        ;Already on stack
  605.         mov    dx, JoyPort
  606.         in    al, dx
  607.         shr    al, 4
  608.         xor    al, 0Fh        ;Invert all switches.
  609.         and    ax, 0Fh        ;Set other bits to zero.
  610.         pop    bx
  611.         iret
  612. Read16Sw    endp
  613.  
  614.  
  615. ;****************************************************************************
  616. ;
  617. ; MyInt15-    Patch for the BIOS INT 15 routine to control reading the
  618. ;        joystick.
  619.  
  620. MyInt15        proc    far
  621.         push    bx
  622.         cmp    ah, 84h            ;Joystick code?
  623.         je    DoJoystick
  624. OtherInt15:    pop    bx
  625.         jmp    cs:Int15Vect
  626.  
  627. DoJoystick:    mov    bh, 0
  628.         mov    bl, dh
  629.         cmp    bl, 80h
  630.         jae    VendorCalls
  631.         cmp    bx, JmpSize
  632.         jae    OtherInt15
  633.         shl    bx, 1
  634.         jmp    wp cs:jmptable[bx]
  635.  
  636. jmptable    word    BIOS
  637.         word    ReadPot, Read4Pots, CalPot, TestCal
  638.         word    ReadRaw, OtherInt15, OtherInt15
  639.         word    ReadSw, Read16Sw
  640. JmpSize        =    ($-jmptable)/2
  641.  
  642.  
  643. ; Handle vendor specific calls here.
  644.  
  645. VendorCalls:    je    RemoveDriver
  646.         cmp    bl, 81h
  647.         je    TestPresence
  648.         pop    bx
  649.         jmp    cs:Int15Vect
  650.  
  651.  
  652. ; TestPresence- Returns zero in AX and a pointer to the ID string in ES:BX
  653.  
  654. TestPresence:    pop    bx        ;Get old value off stack.
  655.         sub    ax, ax
  656.         mov    bx, cseg
  657.         mov    es, bx
  658.         lea    bx, IDString
  659.         iret
  660.  
  661. ; RemoveDriver- If there are no other drivers loaded after this one in
  662. ;        memory, disconnect it and remove it from memory.
  663.  
  664. RemoveDriver:
  665.         push    ds
  666.         push    es
  667.         push    ax
  668.         push    dx
  669.  
  670.         mov    dx, cseg
  671.         mov    ds, dx
  672.  
  673. ; See if we're the last routine patched into INT 15h
  674.  
  675.         mov    ax, 3515h
  676.         int    21h
  677.         cmp    bx, offset MyInt15
  678.         jne    CantRemove
  679.         mov    bx, es
  680.         cmp    bx, wp seg MyInt15
  681.         jne    CantRemove
  682.  
  683.         mov    ax, PSP            ;Free the memory we're in
  684.         mov    es, ax
  685.         push    es
  686.         mov    ax, es:[2ch]         ;First, free env block.
  687.         mov    es, ax
  688.         mov    ah, 49h
  689.         int    21h
  690.  
  691.         pop    es            ;Now free program space.
  692.         mov    ah, 49h
  693.         int    21h
  694.  
  695.         lds    dx, Int15Vect        ;Restore previous int vect.
  696.         mov    ax, 2515h
  697.         int    21h
  698.  
  699. CantRemove:    pop    dx
  700.         pop    ax
  701.         pop    es
  702.         pop    ds
  703.         pop    bx
  704.         iret
  705. MyInt15        endp
  706. cseg        ends
  707.  
  708.  
  709.  
  710. Initialize    segment    para public 'INIT'
  711.         assume    cs:Initialize, ds:cseg
  712. Main        proc
  713.         mov    ax, cseg        ;Get ptr to vars segment
  714.         mov    es, ax
  715.         mov    es:PSP, ds        ;Save PSP value away
  716.         mov    ds, ax
  717.  
  718.         mov    ax, zzzzzzseg
  719.         mov    es, ax
  720.         mov    cx, 100h
  721.         meminit2
  722.  
  723.         print
  724.         byte    "╓───────────────────────────────────────╖",cr,lf
  725.         byte    "║ Standard Game Device Interface driver ║",cr,lf
  726.         byte    "║ PC Compatible Game Adapter Cards      ║",cr,lf
  727.         byte    "║ Written by Randall Hyde               ║",cr,lf
  728.         byte    "╙───────────────────────────────────────╜",cr,lf
  729.         byte    cr,lf
  730.         byte    "'SGDI REMOVE' removes the driver from memory",cr,lf
  731.         byte    lf
  732.         byte    0
  733.  
  734.         mov    ax, 1
  735.         argv                ;If no parameters, empty str.
  736.         stricmpl
  737.         byte    "REMOVE",0
  738.         jne    NoRmv
  739.  
  740.         mov    dh, 81h        ;Remove opcode.
  741.         mov    ax, 84ffh
  742.         int    15h        ;See if we're already loaded.
  743.         test    ax, ax        ;Get a zero back?
  744.         jz    Installed
  745.         print
  746.         byte    "SGDI driver is not present in memory, REMOVE "
  747.         byte    "command ignored.",cr,lf,0
  748.         mov    ax, 4c01h    ;Exit to DOS.
  749.         int    21h
  750.  
  751. Installed:    mov    ax, 8400h
  752.         mov    dh, 80h        ;Remove call
  753.         int     15h
  754.         mov    ax, 8400h
  755.         mov    dh, 81h        ;TestPresence call
  756.         int    15h
  757.         cmp    ax, 0
  758.         je    NotRemoved
  759.         print
  760.         byte    "Successfully removed SGDI driver from memory."
  761.         byte    cr,lf,0
  762.         mov    ax, 4c01h    ;Exit to DOS.
  763.         int    21h
  764.  
  765. NotRemoved:    print
  766.         byte    "SGDI driver is still present in memory.",cr,lf,0
  767.         mov    ax, 4c01h    ;Exit to DOS.
  768.         int    21h
  769.  
  770.  
  771.  
  772. NoRmv:
  773.  
  774.  
  775. ; Okay, Patch INT 15 and go TSR at this point.
  776.  
  777. SwappedLeft:    mov    ax, 3515h
  778.         int    21h
  779.         mov    wp Int15Vect, bx
  780.         mov    wp Int15Vect+2, es
  781.  
  782.         mov    dx, cseg
  783.         mov    ds, dx
  784.         mov    dx, offset MyInt15
  785.         mov    ax, 2515h
  786.         int    21h
  787.  
  788.         mov    dx, cseg
  789.         mov    ds, dx
  790.         mov    dx, seg Initialize
  791.         sub    dx, ds:psp
  792.         add    dx, 2
  793.         mov    ax, 3100h        ;Do TSR
  794.         int    21h
  795. Main        endp
  796.  
  797. Initialize    ends
  798.  
  799.  
  800.  
  801.  
  802. sseg        segment    para stack 'stack'
  803.         dw    128 dup (0)
  804. endstk        dw    ?
  805. sseg        ends
  806.  
  807.  
  808. zzzzzzseg    segment    para public 'zzzzzzseg'
  809.         db     16 dup (0)
  810. zzzzzzseg    ends
  811.         end    Main
  812.